package be.groept.ace.cursusplanning.persistency;

/**
 * 
 * @author Gouke Leplat
 * 
 * Helper voor het opbouwen van de string om een object weg te schrijven.
 * Zorgt voor uniformiteit
 * 
 */

public class SaveStringBuilder {

	private static SaveStringBuilder builder = new SaveStringBuilder();
	

	/**
	 * Geeft in een String de opdrachtregel om een object te late genereren door de objectbuilder
	 * 
	 * @param klasse
	 * 			de klasse waarvan de opdrachtregel moet geschreven worden
	 * @param params
	 * 			de objecten waarmee we de handtekening van de CTOR zullen zoeken en tevens de waarden
	 * 			die zullen gebruikt worden bij creatie
	 * @return 	de opdrachtregel
	 * 	
	 */
	public Object[] CreateObject(Persisteerbaar klasse, Object[] params, Object[] arrayToOutputTo){
		String output = "";
		
		// CTOR
		output = "@CreateObject;" + klasse.getClass().getName() + "#" + klasse.hashCode() +  ";";
		arrayToOutputTo = addToArray(arrayToOutputTo, output);
		//ParameterTypes
		output = builder.ParameterTypes(params);
		arrayToOutputTo = addToArray(arrayToOutputTo, output);
		// @PARAM
		arrayToOutputTo = builder.Parameters(params, arrayToOutputTo);
		
		return arrayToOutputTo;
	}

	/**
	 * voegt een object toe aan een array en geeft de uitgebreide array terug
	 * 
	 * @param arrToAddTo
	 * @param newObject
	 * @return de uitgebreide array
	 */
	public Object[] addToArray(Object[] arrToAddTo,Object newObject){
		
		Object[] newArray = new Object[arrToAddTo.length + 1];
		
		for (int i = 0; i < arrToAddTo.length;i++){
			newArray[i] = arrToAddTo[i];
		}
		
		newArray[newArray.length - 1] = newObject;
		return newArray;
		
	}

	/**
	 * 
	 * @param Methodname
	 * 			De naam van de methode die moet aangeroepen worden bij creatie van het object
	 * @param  params
	 * 			De parameters die nodig zijn om de methode te vinden (handtekening) en uit te voeren
	 * @return De opdrachtregel om een methode uit te voeren
	 */
	public Object[] Method(String Methodname, Object[] params, Object[] arrayToOutputTo){
		
		String output = "";
		
		output = "@Method;" + Methodname +";";	arrayToOutputTo = addToArray(arrayToOutputTo, output);
		output = builder.ParameterTypes(params);					arrayToOutputTo = addToArray(arrayToOutputTo, output);
		
		for (int i = 0; i < params.length; i++){
			
			output = "@Param;" + params[i].getClass().getName() + ";";		
					
			if (isPrimitiveType(params[i]) || params[i].getClass().isEnum()){
				
				output += "@Value;" + params[i] +";";	
						
			}
			else{
				output += "@CreateObject;"  + params[i].getClass().getName() + "#" + params[i].hashCode() +  ";"; 	
			}
			
			arrayToOutputTo = addToArray(arrayToOutputTo, output);
		}
		
		output = "@EndParams;";   
		arrayToOutputTo = addToArray(arrayToOutputTo, output);
		
		return arrayToOutputTo;
	}
	
	/**
	 * Geeft een String waarmee de objectbuilder de parameterTypes kan bepalen voor een CTOR of een methode
	 * 
	 * @param objects
	 * @return ParameterTypes
	 * 			
	 */
	private String ParameterTypes(Object[] objects){
		String output = "";
		output = "@ParameterTypes;";
		
				
		for (int i = 0; i < objects.length; i++){
			output += objects[i].getClass().getName() +";";
		}
		
		return output;
	}
	
	/**
	 * Geeft een string over meerdere lijnen waarmee per lijn een parameterobject kan aangemaakt worden
	 * 
	 * @param params
	 * @return opdrachtregel
	 */
	@SuppressWarnings("rawtypes")
	private Object[] Parameters (Object[] params, Object[] arrayToOutputTo){
		String output = "";
		
		
		for (int i = 0; i < params.length; i++){
			
	
			output = "@Param;" + params[i].getClass().getName() + ";";
			
	
			// PRIMITIEF DATATYPE
			if (builder.isPrimitiveType(params[i])){
				output += "@Value;" + params[i] + ";";
			} // ENUMERATIE
			else if ( params[i].getClass().isEnum()){
				
				output += "@Value;" + ((Enum) params[i]).toString() + ";"; 
			}// OBJECT
			else{
				output += "@CreateObject;" + params[i].getClass().getName() + "#" + params[i].hashCode() +  ";";
				
			}
			arrayToOutputTo = addToArray(arrayToOutputTo, output);
		}
		
		output = "@EndParams;";
		arrayToOutputTo = addToArray(arrayToOutputTo, output);
		
		return arrayToOutputTo;
	}

	/**
	 * Bepaalt of het object een primitief type vertegenwoordigd of niet.
	 * @param obj
	 * @return boolean
	 */
	private boolean isPrimitiveType(Object obj){
		/* WERKT NIET ?????
		String Tpe = obj.getClass().getSimpleName();
		
		if (Tpe == "String" || Tpe == "Integer" || Tpe == "Char" || Tpe == "Boolean" 
			|| Tpe == "Byte" || Tpe == "Short" || Tpe == "Long" || Tpe == "Float" || Tpe == "Double"){
			System.out.println("TRUETpe: " + Tpe);
			return true;
		}
		*/
		Class<?> ref = obj.getClass();
		
		short sho = 0;
		long lon = 0;
		byte bte = 0;
		
		String S = new String();
		Integer I = new Integer(0);
		Character C = new Character((char) 60);
		Boolean B = new Boolean(false);
		Byte BY = new Byte(bte);
		Short SH = new Short(sho);
		Long L = new Long(lon);
		Float F = new Float(1);
		Double Do = new Double(0);

		if( ref == S.getClass() || ref == I.getClass()|| ref == C.getClass()|| ref == B.getClass()|| ref == BY.getClass()
				|| ref == SH.getClass()|| ref == L.getClass()|| ref == F.getClass()|| ref == Do.getClass()){
			return true;
		}
		
		
		
		return false;

	}
}
